﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using System.IO;
using System.Data;
using System.Data.SqlClient;
using System.Xml;
using BrokerBase.Lib.Tool;

namespace BrokerBase.Lib.DataBase
{

    public enum TableType{Data=0,Score=1}

    public class DBTable
    {
        public DBTable()
        {

        }

        public virtual int Id { get; set; }

        public virtual string Name { get; set; }

        public virtual TableType TableType { get; set; }

        public virtual string SQL { get; set; }

        public virtual bool IsNeedUpdate { get; set; }

        public virtual bool IsIdentity { get; set; }

        public virtual long LastTimeStamp { get; set; }

        public virtual string Description { get; set; }

        public virtual DBTableData TableData { get; set; }


        public virtual void SetServerTableData(DBTableData data)
        {
            TableData.ClientMaxId = data.ClientMaxId;
            TableData.ClientMinId = data.ClientMinId;
            TableData.ClientRowCount = data.ClientRowCount;
            TableData.ClientTs = data.ClientTs;
            TableData.Data = data.Data;
            TableData.Description = data.Description;
            TableData.IsExistDeletedRows = data.IsExistDeletedRows;
            TableData.IsSuccess = data.IsSuccess;
            TableData.Name = data.Name;
            TableData.NoExistId = data.NoExistId;
            TableData.Ids = data.Ids;
            TableData.ServerMaxId = data.ServerMaxId;
            TableData.ServerMinId = data.ServerMinId;
            TableData.ServerNewRowCount = data.ServerNewRowCount;
            TableData.ServerRowCount = data.ServerRowCount;
            TableData.ServerTs = data.ServerTs;

        }

        public virtual long LoadLastTimeStamp(ISession sess)
        {
            long? ts = sess.CreateSQLQuery("select cast(max(ts) as bigint) from " + Name).UniqueResult<long>();

            return ts == null ? 0 : (long)ts;
        }

        public virtual DBTableData LoadData(long clientMinRow, long clientMaxRow, long clientRowCount, long clientTs,string sqlWhere, SqlConnection cnn)
        {
            try
            {
                DBTableData ta = GetDBTableDataBaseInfo(clientMinRow, clientMaxRow, clientRowCount, clientTs, sqlWhere, cnn);

                //Debug.Assert(Name != "Product_FixRateRecord");
                string sql = null;

                if (ta.ClientTs != ta.ServerTs)//有修改或新增的数据需要下载
                {

                    sql = string.Format("select * from ({0}) as x where ts> cast({1} as timestamp) and ts<= cast({2} as timestamp) ", SQL + sqlWhere, clientTs, ta.ServerTs);

                    //sql = "select * from " + Name + " where ts> " + clientTs + " and ts<= cast(" + ta.ServerTs + " as timestamp)";

                    DataSet ds = new DataSet(Name);
                    IDataAdapter da = new SqlDataAdapter(sql, cnn);

                    da.Fill(ds);

                    StringBuilder content = new StringBuilder();
                    StringWriter writer = new StringWriter(content);
                    XmlTextWriter xmlWriter = new XmlTextWriter(writer);

                    ds.WriteXml(xmlWriter, XmlWriteMode.WriteSchema);

                    string s = content.ToString();
                    byte[] data = TransportUtil.CompressText(s);
                    ta.Data = data;

                    content.Clear();
                    ds.Clear();

                    ds.Dispose();



                }
                //判断是否存在需要删除的数据
                if (IsExistDeletedRows(ta, cnn))
                {
                    //获取当前表的所有id
                    sql = "select id from " + Name;

                    SqlCommand cmd = cnn.CreateCommand();
                    cmd.CommandText = sql;

                    SqlDataReader reader = cmd.ExecuteReader();

                    IList<int> result = new List<int>();
                    while (reader.Read())
                    {
                        result.Add(reader.GetInt32(0));
                    }

                    reader.Close();
                    reader.Dispose();
                    cmd.Dispose();

                    int[] ids = result.ToArray<int>();

                    ta.Ids = ids;
                }
                return ta;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 获取表数据的基本信息
        /// </summary>
        /// <param name="clientMinRow"></param>
        /// <param name="clientMaxRow"></param>
        /// <param name="clientRowCount"></param>
        /// <param name="clientTs"></param>
        /// <param name="cnn"></param>
        /// <returns></returns>
        private DBTableData GetDBTableDataBaseInfo(long clientMinRow, long clientMaxRow, long clientRowCount, long clientTs,string sqlWhere ,SqlConnection cnn)
        {
            try
            {
                DBTableData ta = new DBTableData();
                ta.Name = this.Name;
                ta.ClientMinId = clientMinRow;
                ta.ClientMaxId = clientMaxRow;
                ta.ClientRowCount = clientRowCount;
                ta.ClientTs = clientTs;

                SqlCommand cmd = cnn.CreateCommand();
                SqlDataReader reader = null;

                string sql = "select LastTimeStamp from System_TableUpdate where Name='" + Name + "'";

                cmd.CommandText = sql;

                long lastTs = Convert.ToInt64(cmd.ExecuteScalar());


                if (Name == "Score_ScoreRecord")
                {
                    cmd.CommandText = "select cast(isnull(max(ts),0) as bigint) from (" + SQL + sqlWhere + ") as x";
                    ta.ServerTs = Convert.ToInt64(cmd.ExecuteScalar());
                }
                else
                {
                    ta.ServerTs = lastTs;
                }

                sql = "select count(*) as c,isnull(min(id),0) as minId,isnull(max(id),0) as maxId from (" + SQL + sqlWhere + ")as x where Ts<=cast(" + ta.ServerTs + " as timestamp)";
                cmd.CommandText = sql;
                reader = cmd.ExecuteReader();

                if (reader.Read())
                {
                    ta.ServerRowCount = Convert.ToInt64(reader.GetValue(0));
                    ta.ServerMinId = Convert.ToInt64(reader.GetValue(1));
                    ta.ServerMaxId = Convert.ToInt64(reader.GetValue(2));
                }

                reader.Close();
                reader.Dispose();

                sql = "select count(*) as c from (" + SQL + sqlWhere + ")as x where id>" + ta.ClientMaxId + " and ts>cast(" + ta.ClientTs + " as timestamp) and ts<=cast(" + ta.ServerTs + " as timestamp)";

                cmd.CommandText = sql;
                long c = Convert.ToInt64(cmd.ExecuteScalar());

                ta.ServerNewRowCount = c;

                return ta;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private bool IsExistDeletedRows(DBTableData ta, IDbConnection cnn)
        {

            //客户端与服务器端行数相同，并且时间戳也相同，表示没有需要删除的行
            if (ta.ServerTs == ta.ClientTs && ta.ServerRowCount == ta.ClientRowCount)
                ta.IsExistDeletedRows = false;
            //服务器端增加的行数等于来服务器、客户端端之差
            else if (ta.ServerRowCount - ta.ClientRowCount == ta.ServerNewRowCount)
                ta.IsExistDeletedRows = false;
            else
                ta.IsExistDeletedRows = true;
            return ta.IsExistDeletedRows;
        }

   }
}
